﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK.Graphics.OpenGL;
namespace Foundry.Graphics
{

    public enum AttributeType
    {
        Position,
        Normal,
        TexCoord0,
        TexCoord1,
        TexCoord2,
        TexCoord3,
        Weight,

    }

    [AttributeUsage(AttributeTargets.Field)]
    public class VertexDataTypeAttribute : Attribute
    {
    }
	
	/// <summary>
	/// Tells the shader to ignore this field 
	/// </summary>
    [AttributeUsage(AttributeTargets.Field)]
    public class IgnoreAttribute : Attribute
    {
		
    }
	/// <summary>
	/// Overrides default behaviour of determining datatype of the field 
	/// </summary>
    [AttributeUsage(AttributeTargets.Field)]
    public class CustomTypeAttribute : Attribute
    {
        public DataType Type;
    }
	
	/// <summary>
	/// Specifies the field name which contains the descriptor for the structure. 
	/// </summary>
    [AttributeUsage(AttributeTargets.Struct)]
    public class DescriptorAttribute : Attribute
    {
		public DescriptorAttribute()
		{
			DescriptorFieldName = "Descriptor";
		}
		public DescriptorAttribute(string fieldname)
		{
			DescriptorFieldName = fieldname;
		}
        public string DescriptorFieldName;
    }
	
	/// <summary>
	/// Ovverides the default behavior and speciricly assigns an index to a field. 
	/// </summary>
    [AttributeUsage(AttributeTargets.Field)]
    public class ElementIndexAttribute : Attribute
    {
        public int Index;
    }
	/// <summary>
	/// Alias to a field in a vertexshader 
	/// </summary>
    [AttributeUsage(AttributeTargets.Field)]
    public class ElementNameAttribute : Attribute
    {
        public string FieldName;
    }

    public enum DataType
    {
        Ignore,
        UByte = 0x11,
        Byte = 0x21,
        UShort = 0x31,
        Short = 0x41,
        UInt = 0x51,
        Int = 0x61,
        Half = 0x10,
        Float = 0x20,
        Double = 0x30
    }

    public class VertexDescriptor
    {

        public sealed class VertexElement
        {
            public string Name { get; private set; }
            public DataType Type { get; private set; }
            public Type FieldType { get; private set; }
            public int Elements { get; private set; }
            public int Offset { get; private set; }
            internal VertexElement(string name, DataType type, Type fieldtype, int elements, int offset)
            {
                Name = name;
                Type = type;
                FieldType = fieldtype;
                Elements = elements;
                Offset = offset;
            }
        }

        List<VertexElement> list_elements;
        public int TotalSize { get; private set; }
        public System.Collections.ObjectModel.ReadOnlyCollection<VertexElement> Items { get { return list_elements.AsReadOnly(); } }

        public VertexDescriptor(Type t)
        {
            var fields = t.GetFields();
            int offset = 0;
            list_elements = new List<VertexElement>();
            TotalSize = System.Runtime.InteropServices.Marshal.SizeOf(t);
            foreach (var field in fields.Where(item => !item.IsStatic))
            {
                VertexElement elm;
                string name = field.Name;
                DataType type = DataType.Ignore;
                int size = System.Runtime.InteropServices.Marshal.SizeOf(field.FieldType);
                int elements = 1;
                var items = field.GetCustomAttributes(typeof(IgnoreAttribute), false);
                
                if (items == null || items.Length == 0)
                {
                    var types = field.GetCustomAttributes(typeof(CustomTypeAttribute), false);
                    if (types != null && types.Length > 0)
                    {
                        type = (types[0] as CustomTypeAttribute).Type;
                    }
                    else
                    {
                        if (field.FieldType == typeof(byte))
                            type = DataType.UByte;
                        else if (field.FieldType == typeof(sbyte))
                            type = DataType.Byte;
                        else if (field.FieldType == typeof(ushort))
                            type = DataType.UShort;
                        else if (field.FieldType == typeof(short))
                            type = DataType.Short;
                        else if (field.FieldType == typeof(uint))
                            type = DataType.UInt;
                        else if (field.FieldType == typeof(int))
                            type = DataType.Int;
                        else if (field.FieldType == typeof(OpenTK.Half))
                            type = DataType.Half;
                        else if (field.FieldType == typeof(float))
                            type = DataType.Float;
                        else if (field.FieldType == typeof(double))
                            type = DataType.Double;
                        else if (field.FieldType == typeof(OpenTK.Quaternion))
                        {
                            type = DataType.Float;
                            elements = 4;
                        }
                        else if (field.FieldType == typeof(OpenTK.Quaterniond))
                        {
                            type = DataType.Double;
                            elements = 4;
                        }
                        else if (field.FieldType == typeof(OpenTK.Matrix4))
                            type = DataType.Float;
                        else if (field.FieldType == typeof(OpenTK.Matrix4d))
                            type = DataType.Double;
                        else if (field.FieldType == typeof(OpenTK.Vector2))
                        {
                            type = DataType.Float;
                            elements = 2;
                        }
                        else if (field.FieldType == typeof(OpenTK.Vector3))
                        {
                            type = DataType.Float;
                            elements = 3;
                        }
                        else if (field.FieldType == typeof(OpenTK.Vector4))
                        {
                            type = DataType.Float;
                            elements = 4;
                        }

                        else if (field.FieldType == typeof(OpenTK.Vector2h))
                        {
                            elements = 2;
                            type = DataType.Half;
                        }
                        else if (field.FieldType == typeof(OpenTK.Vector3h))
                        {
                            elements = 3;
                            type = DataType.Half;
                        }
                        else if (field.FieldType == typeof(OpenTK.Vector4h))
                        {
                            elements = 4;
                            type = DataType.Half;
                        }
                        else if (field.FieldType == typeof(OpenTK.Vector2d))
                        {
                            elements = 2;
                            type = DataType.Double;
                        }
                        else if (field.FieldType == typeof(OpenTK.Vector3d))
                        {
                            elements = 3;
                            type = DataType.Double;
                        }
                        else if (field.FieldType == typeof(OpenTK.Vector4d))
                        {
                            elements = 4;
                            type = DataType.Double;
                        }
                        else
                            type = DataType.Ignore;
                    }
                }
                else
                    type = DataType.Ignore;
                elm = new VertexElement(name, type, field.FieldType, elements, offset);
                list_elements.Add(elm);
                offset += size;

            }
        }

    }

    public class VertexBuffer<T> : Buffer<T>
        where T : struct
    {
        public VertexBuffer()
            : base(OpenTK.Graphics.OpenGL.BufferTarget.ArrayBuffer)
        {
        }


    }
}
